package com.test.redis.service;

import com.test.redis.entity.DataSourceConfig;
import com.test.redis.entity.DataSourceMessage;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态数据源管理器
 * 负责数据源的创建、更新、销毁和路由
 */
@Slf4j
@Component
public class DynamicDataSourceManager {
    
    /**
     * 存储所有动态数据源的Map
     */
    private final Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();
    
    @Autowired
    private DataSourceConfigMapper dataSourceConfigMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Value("${spring.application.instance-id:default}")
    private String instanceId;
    
    /**
     * 应用启动时初始化数据源
     */
    public void initDataSources() {
        log.info("开始初始化动态数据源...");
        
        // 查询所有启用的数据源配置
        List<DataSourceConfig> configs = dataSourceConfigMapper.selectList(null);
        
        for (DataSourceConfig config : configs) {
            if (config.getStatus() == 1) {
                try {
                    createDataSource(config);
                    log.info("成功创建数据源: {}", config.getName());
                } catch (Exception e) {
                    log.error("创建数据源失败: {}, 错误: {}", config.getName(), e.getMessage());
                }
            }
        }
        
        log.info("动态数据源初始化完成，共初始化 {} 个数据源", dataSourceMap.size());
    }
    
    /**
     * 创建数据源
     */
    public synchronized void createDataSource(DataSourceConfig config) {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(config.getDriverClassName());
        dataSource.setJdbcUrl(config.getUrl());
        dataSource.setUsername(config.getUsername());
        dataSource.setPassword(config.getPassword());
        dataSource.setMaximumPoolSize(config.getMaxPoolSize() != null ? config.getMaxPoolSize() : 10);
        dataSource.setMinimumIdle(config.getMinIdle() != null ? config.getMinIdle() : 5);
        dataSource.setPoolName("HikariPool-" + config.getName());
        
        dataSourceMap.put(config.getName(), dataSource);
        log.info("数据源创建成功: {}", config.getName());
    }
    
    /**
     * 更新数据源
     */
    public synchronized void updateDataSource(DataSourceConfig config) {
        String name = config.getName();
        
        if (dataSourceMap.containsKey(name)) {
            // 关闭旧的数据源
            DataSource oldDataSource = dataSourceMap.get(name);
            if (oldDataSource instanceof HikariDataSource) {
                ((HikariDataSource) oldDataSource).close();
            }
            // 创建新的数据源
            createDataSource(config);
            log.info("数据源更新成功: {}", name);
        } else {
            log.warn("尝试更新不存在的数据源: {}", name);
        }
    }
    
    /**
     * 删除数据源
     */
    public synchronized void removeDataSource(String datasourceName) {
        if (dataSourceMap.containsKey(datasourceName)) {
            DataSource dataSource = dataSourceMap.remove(datasourceName);
            if (dataSource instanceof HikariDataSource) {
                ((HikariDataSource) dataSource).close();
            }
            log.info("数据源删除成功: {}", datasourceName);
        }
    }
    
    /**
     * 获取数据源
     */
    public DataSource getDataSource(String name) {
        return dataSourceMap.get(name);
    }
    
    /**
     * 获取所有数据源名称
     */
    public List<String> getDataSourceNames() {
        return List.copyOf(dataSourceMap.keySet());
    }
    
    /**
     * 发布数据源变更消息
     */
    public void publishDataSourceChange(DataSourceMessage.MessageType type, String datasourceName) {
        DataSourceMessage message = new DataSourceMessage();
        message.setType(type);
        message.setDatasourceName(datasourceName);
        message.setTimestamp(System.currentTimeMillis());
        message.setInstanceId(instanceId);
        
        redisTemplate.convertAndSend("datasource-channel", message);
        log.info("发布数据源变更消息: {} - {}", type, datasourceName);
    }
    
    /**
     * 处理接收到的数据源变更消息
     */
    public void handleDataSourceMessage(DataSourceMessage message) {
        // 避免处理自己发送的消息
        if (instanceId.equals(message.getInstanceId())) {
            return;
        }
        
        log.info("接收到数据源变更消息: {} - {}", message.getType(), message.getDatasourceName());
        
        switch (message.getType()) {
            case CREATE:
            case UPDATE:
                // 查询最新的数据源配置并更新
                DataSourceConfig config = dataSourceConfigMapper.selectById(message.getDatasourceName());
                if (config != null && config.getStatus() == 1) {
                    if (dataSourceMap.containsKey(config.getName())) {
                        updateDataSource(config);
                    } else {
                        createDataSource(config);
                    }
                }
                break;
                
            case DELETE:
                removeDataSource(message.getDatasourceName());
                break;
                
            case REFRESH_ALL:
                refreshAllDataSources();
                break;
        }
    }
    
    /**
     * 刷新所有数据源
     */
    private void refreshAllDataSources() {
        log.info("开始刷新所有数据源...");
        
        // 获取当前所有启用的数据源配置
        List<DataSourceConfig> currentConfigs = dataSourceConfigMapper.selectList(null);
        Map<String, DataSourceConfig> configMap = new HashMap<>();
        
        for (DataSourceConfig config : currentConfigs) {
            if (config.getStatus() == 1) {
                configMap.put(config.getName(), config);
            }
        }
        
        // 更新或创建数据源
        for (DataSourceConfig config : configMap.values()) {
            if (dataSourceMap.containsKey(config.getName())) {
                updateDataSource(config);
            } else {
                createDataSource(config);
            }
        }
        
        // 删除不存在的数据源
        List<String> toRemove = dataSourceMap.keySet().stream()
                .filter(name -> !configMap.containsKey(name))
                .toList();
        
        for (String name : toRemove) {
            removeDataSource(name);
        }
        
        log.info("数据源刷新完成");
    }
}